﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Tradex.ComponentModel {
    
    /// <summary>
    /// An Entity is a dynamically updating object in Tradex.
    /// </summary>
    [Serializable()]
    public abstract class Entity<T>
        : INotifyPropertyChanged
        where T : EntityKey
    {

        /// <summary>
        /// Constructor for subclasses. This requires the Key to be Post-Configured.
        /// </summary>
        protected Entity() {
        }

        /// <summary>
        /// This protected constructor is called by subclasses. Takes the Key as argument.
        /// </summary>
        /// <param name="key"></param>
        protected Entity (T key) {
            Key = key;
        }

        T _Key;

        /// <summary>
        /// This is the Key of the item.
        /// </summary>
        public T Key {
            get { return _Key; }
            set {
                if (_Key == value) {
                    return;
                }
                if (_Key != null) {
                    throw new InvalidOperationException("Key already set");
                }
                _Key = value;
                OnPropertyChanged("Key");
            }
        }

        /// <summary>
        /// The OnPropertyChanged method trows the PropertyChanged event handler if reasonable. This overload does not set
        /// or compare values, and should thus only be used to throw the PropertyChanged event for secondary / computed properties.
        /// </summary>
        /// <param name="property"></param>
        protected void OnPropertyChanged(string property) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }

        /// <summary>
        /// The OnPropetyChanged event handler. it is programmed in such a way to not throw an event if
        /// old and new value are identical, and otherwise be usable in only one code line.
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="property"></param>
        /// <param name="oldValue"></param>
        /// <param name="newValue"></param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045")]
        protected void OnPropertyChanged<V>(string property, ref V oldValue, V newValue) {
            if (!System.Object.Equals(oldValue, newValue)) {
                oldValue = newValue;
                OnPropertyChanged(property);
            }
            return;
        }

        /// <inheritdoc />
        public event PropertyChangedEventHandler PropertyChanged;

    }

}
